﻿
using DataService.Cache.IService;
using DataService.Core.Reflection;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;

namespace DataService.Cache.Caching
{
    public class DataMemoryCache : Cache
    {
        #region 静态默认实现
        /// <summary>默认缓存</summary>
        public static DataMemoryCache Instance { get; set; } = new DataMemoryCache();
        #endregion
        protected MemoryCache _memoryCache { get; set; }
        public DataMemoryCache()
        {
            MemoryCacheOptions cacheOps = new MemoryCacheOptions()
            {
                //缓存最大量
                //##注意netcore中的缓存是没有单位的，缓存项和缓存的相对关系
                SizeLimit = 100000,
                //缓存满了时，压缩20%（即删除20份优先级低的缓存项）
                CompactionPercentage = 0.2,
                //60秒钟查找一次过期项
                ExpirationScanFrequency = TimeSpan.FromSeconds(60),

            };
            _memoryCache = new MemoryCache(cacheOps);
        }
        #region 缓存属性
        private Int32 _count;
        /// <summary>缓存项。原子计数</summary>
        public override Int32 Count => _count;

        /// <summary>所有键。实际返回只读列表新实例，数据量较大时注意性能</summary>
        public override ICollection<String> Keys => GetAllKeys() ?? new List<string>();
        #endregion
        /// <summary>是否包含缓存项</summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public override bool ContainsKey(string key)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            return _memoryCache.TryGetValue(key, out _);
        }

        public override T Get<T>(string key)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));

            return _memoryCache.Get(key).ChangeType<T>();
        }
        public object Get(string key)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));

            return _memoryCache.Get(key);
        }
        public override TimeSpan GetExpire(string key)
        {
            throw new NotImplementedException();
        }
        /// <summary>批量移除缓存项</summary>
        /// <param name="keys">键集合</param>
        /// <returns>实际移除个数</returns>
        public override int Remove(params string[] keys)
        {
            if (keys == null)
                throw new ArgumentNullException(nameof(keys));
            int count = 0;

            foreach (var item in keys)
            {

                count++;
                _memoryCache.Remove(item);
                Interlocked.Decrement(ref _count);

            }
            return count;
        }
        /// <summary>添加缓存项，已存在时更新</summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="expire">过期时间，秒</param>
        /// <returns></returns>
        public override bool Set<T>(string key, T value, int expire = -1)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));
            if (expire <= 0)
            {
                _memoryCache.Set<T>(key, value);
            }
            else
            {
                TimeSpan tempexpiressAbsoulte = TimeSpan.FromSeconds(expire);
                var tempOption = new MemoryCacheEntryOptions();
                tempOption.AbsoluteExpirationRelativeToNow = tempexpiressAbsoulte;
                tempOption.Size = 1;
                _memoryCache.Set<T>(key, value, tempOption);
            }
            Interlocked.Increment(ref _count);
            return true;
        }


        private bool Set(string key, object value, int expire = -1)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));
            //if (ContainsKey(key))
            //{
            //    throw new ArgumentNullException($"{key}已存在");
            //}
            if (expire <= 0)
            {
                _memoryCache.Set(key, value);
            }
            else
            {
                TimeSpan tempexpiressAbsoulte = TimeSpan.FromSeconds(expire);
                var tempOption = new MemoryCacheEntryOptions();
                tempOption.AbsoluteExpirationRelativeToNow = tempexpiressAbsoulte;
                tempOption.Size = 1;
                _memoryCache.Set(key, value, tempOption);
            }

            Interlocked.Increment(ref _count);
            return true;
        }

        /// <summary>设置缓存项有效期（不推荐使用 DataMemoryCache.SetExpire）</summary>
        /// <param name="key">键</param>
        /// <param name="expire">过期时间；TimeSpan.FromMilliseconds(毫秒)</param>
        /// <returns>设置是否成功</returns>
        public override bool SetExpire(string key, TimeSpan expire)
        {
            object value = Get(key);

            Set(key, value, expire.Seconds);
            return true;
        }

        public List<string> GetAllKeys()
        {
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var entries = _memoryCache.GetType().GetField("_entries", flags).GetValue(_memoryCache);
            var cacheItems = entries as IDictionary;
            var keys = new List<string>();
            if (cacheItems == null) return keys;
            foreach (DictionaryEntry cacheItem in cacheItems)
            {
                keys.Add(cacheItem.Key.ToString());
            }
            return keys;
        }
    }
}
